<template>
  <div class="steve-category-tools">
    <t-drawer
      v-model:visible="visibleTools"
      header="榜单设置"
      size="50%"
      :close-on-overlay-click="false"
      :destroy-on-close="true"
      @cancel="visibleTools = false"
      @confirm="onConfirm"
    >
      <div class="structure">
        <div class="structure-body">
          <t-form>
            <t-space :size="10" direction="vertical">
              <t-divider align="left">构造地址</t-divider>
              <div class="structure-body__url">
                <div class="structure-body__url__type">
                  <t-radio-group v-model="structureType" size="small" variant="default-filled">
                    <t-radio-button :value="1">构造分组</t-radio-button>
                    <t-radio-button :value="2">快捷操作</t-radio-button>
                  </t-radio-group>
                </div>
                <t-textarea
                  v-model="formData.structure"
                  placeholder="请输入榜单页面完整的URL地址或路径(即不包含host的path)，使用鼠标选中或直接根据规则修改即可构造相应的分组以及参数"
                  :autosize="{ minRows: 3, maxRows: 5 }"
                  @mouseup="onSelectStructure"
                />
              </div>
              <div v-if="structureType == 1" class="structure-body__param">
                <t-space v-if="isStructureSelect" align="center" size="2px">
                  <t-tag theme="primary" variant="light">@{_</t-tag>
                  <t-input
                    v-model="structureSelectText"
                    placeholder="请输入自定义参数名称"
                    class="structure-body__param__input"
                    size="small"
                  />
                  <t-tag theme="primary" variant="light">}</t-tag>
                  <t-button class="button" size="small" @click="onStructureParamConfirm">确认</t-button>
                  <t-button class="button" theme="default" size="small" @click="onStructureSelectCancel">取消</t-button>
                </t-space>
                <t-tag v-else variant="light" theme="primary">请先选中需要构造的内容</t-tag>
              </div>
              <div v-if="structureType == 2" class="structure-body__param">
                <t-space size="10px">
                  <t-button size="small" @click="onStructureParamShortcut('pageIndex')">添加页码</t-button>
                </t-space>
              </div>
              <div v-if="groupTabsData.length > 0" class="structure-body__group">
                <t-tabs v-model="groupTabsValue" theme="card">
                  <t-tab-panel
                    v-for="(item, key) in groupTabsData"
                    :key="key"
                    :value="key"
                    :label="item.name"
                    :destroy-on-hide="false"
                  >
                    <t-space class="group-body" direction="vertical" :size="10">
                      <div class="group-body__name">
                        <t-input v-model="item.name" placeholder="分组名称，比如，分类、排序、状态等" />
                      </div>
                      <div class="group-body__ace">
                        <steve-ace-editor v-model:value="item.list" :height="300" />
                      </div>
                      <div class="group-body__option">
                        <t-button @click="onConversion">转换</t-button>
                      </div>
                    </t-space>
                  </t-tab-panel>
                </t-tabs>
              </div>
              <t-divider align="right">解析规则</t-divider>
              <t-row class="row-gap">
                <t-col :span="6">
                  <t-form-item label="榜单名称" name="name">
                    <t-input v-model="formData.name" placeholder="榜单名称" />
                  </t-form-item>
                </t-col>
                <t-col :span="6">
                  <t-form-item label="请求模式" name="method">
                    <t-radio-group v-model="formData.mode" size="small" variant="default-filled">
                      <t-radio-button value="http">HTTP</t-radio-button>
                      <t-radio-button value="webview">WebView</t-radio-button>
                    </t-radio-group>
                  </t-form-item>
                </t-col>
              </t-row>
              <t-row class="row-gap">
                <t-col :span="6">
                  <t-form-item :label="$t('pages.source.common.engine')" name="engine">
                    <t-radio-group v-model="formData.engine" size="small" variant="default-filled">
                      <t-radio-button value="xpath">XPATH</t-radio-button>
                      <t-radio-button value="jsonpath">JSONPATH</t-radio-button>
                    </t-radio-group>
                  </t-form-item>
                </t-col>
                <t-col :span="6">
                  <t-form-item label="请求方式" name="method">
                    <t-radio-group v-model="formData.method" size="small" variant="default-filled">
                      <t-radio-button value="GET">GET</t-radio-button>
                      <t-radio-button value="POST">POST</t-radio-button>
                    </t-radio-group>
                  </t-form-item>
                </t-col>
              </t-row>
              <t-row class="row-gap">
                <t-col :span="6">
                  <t-form-item :label="$t('pages.source.common.requestEncode')" name="requestEncode">
                    <t-radio-group v-model="formData.requestEncode" size="small" variant="default-filled">
                      <t-radio-button value="utf-8">UTF-8</t-radio-button>
                      <t-radio-button value="gbk">GBK</t-radio-button>
                    </t-radio-group>
                  </t-form-item>
                </t-col>
                <t-col :span="6">
                  <t-form-item :label="$t('pages.source.common.responseEncode')" name="responseEncode">
                    <t-radio-group v-model="formData.responseEncode" size="small" variant="default-filled">
                      <t-radio-button value="utf-8">UTF-8</t-radio-button>
                      <t-radio-button value="gbk">GBK</t-radio-button>
                    </t-radio-group>
                  </t-form-item>
                </t-col>
              </t-row>
              <t-row v-if="formData.method === 'POST'" class="row-gap">
                <t-col :span="12">
                  <t-form-item label="请求参数" name="params">
                    <steve-textarea v-model:value="formData.params" placeholder="请求参数应该为一个json类型的字符串" />
                  </t-form-item>
                </t-col>
              </t-row>
              <t-row class="row-gap">
                <t-col :span="12">
                  <t-form-item label="最大翻页数" name="pageMax">
                    <steve-textarea v-model:value="formData.pageMax" />
                  </t-form-item>
                </t-col>
              </t-row>
              <t-row class="row-gap">
                <t-col :span="12">
                  <t-form-item
                    :label="$t('pages.source.common.header')"
                    name="header"
                    :help="$t('pages.source.common.mustJson')"
                  >
                    <steve-textarea v-model:value="formData.header" />
                  </t-form-item>
                </t-col>
              </t-row>
              <t-row class="row-gap">
                <t-col :span="12">
                  <t-form-item :label="$t('pages.source.common.request')" :help="$t('pages.source.common.requestHelp')">
                    <steve-textarea v-model:value="formData.request" />
                  </t-form-item>
                </t-col>
              </t-row>
              <t-row class="row-gap">
                <t-col :span="12">
                  <t-form-item
                    :label="$t('pages.source.common.response')"
                    name="response"
                    :help="$t('pages.source.common.responseHelp')"
                  >
                    <steve-textarea v-model:value="formData.response" />
                  </t-form-item>
                </t-col>
              </t-row>
              <t-row class="row-gap">
                <t-col :span="12">
                  <t-form-item label="书籍列表" name="bookList">
                    <steve-textarea v-model:value="formData.bookList" />
                  </t-form-item>
                </t-col>
              </t-row>
              <t-row class="row-gap">
                <t-col :span="12">
                  <t-form-item label="书籍名称" name="bookName">
                    <steve-textarea v-model:value="formData.bookName" />
                  </t-form-item>
                </t-col>
              </t-row>
              <t-row class="row-gap">
                <t-col :span="12">
                  <t-form-item label="书籍地址" name="bookUrl">
                    <steve-textarea v-model:value="formData.bookUrl" />
                  </t-form-item>
                </t-col>
              </t-row>
              <t-row class="row-gap">
                <t-col :span="12">
                  <t-form-item label="书籍作者" name="bookAuthor">
                    <steve-textarea v-model:value="formData.bookAuthor" />
                  </t-form-item>
                </t-col>
              </t-row>
              <t-divider align="right">{{ $t('pages.source.common.extendedRule') }}</t-divider>
              <t-row class="row-gap">
                <t-col :span="12">
                  <t-form-item :label="$t('pages.source.common.bookDescription')" name="ruleExtra.introduce">
                    <steve-textarea v-model:value="formData.ruleExtra.introduce" />
                  </t-form-item>
                </t-col>
              </t-row>
              <t-row class="row-gap">
                <t-col :span="12">
                  <t-form-item :label="$t('pages.source.common.bookCover')" name="ruleExtra.coverUrl">
                    <steve-textarea v-model:value="formData.ruleExtra.coverUrl" />
                  </t-form-item>
                </t-col>
              </t-row>
              <t-row class="row-gap">
                <t-col :span="12">
                  <t-form-item :label="$t('pages.source.common.bookCategory')" name="ruleExtra.classify">
                    <steve-textarea v-model:value="formData.ruleExtra.classify" />
                  </t-form-item>
                </t-col>
              </t-row>
              <t-row class="row-gap">
                <t-col :span="12">
                  <t-form-item :label="$t('pages.source.common.bookSize')" name="ruleExtra.bookSize">
                    <steve-textarea v-model:value="formData.ruleExtra.bookSize" />
                  </t-form-item>
                </t-col>
              </t-row>
              <t-row class="row-gap">
                <t-col :span="12">
                  <t-form-item
                    :label="$t('pages.source.common.bookLatestChapterName')"
                    name="ruleExtra.lastChapterName"
                  >
                    <steve-textarea v-model:value="formData.ruleExtra.lastChapterName" />
                  </t-form-item>
                </t-col>
              </t-row>
              <t-row class="row-gap">
                <t-col :span="12">
                  <t-form-item
                    :label="$t('pages.source.common.bookLatestUpdateTime')"
                    name="ruleExtra.lastUpdateTime"
                  >
                    <steve-textarea v-model:value="formData.ruleExtra.lastUpdateTime" />
                  </t-form-item>
                </t-col>
              </t-row>
              <t-row class="row-gap">
                <t-col :span="12">
                  <t-form-item :label="$t('pages.source.common.bookCompletionStatus')" name="ruleExtra.status">
                    <steve-textarea v-model:value="formData.ruleExtra.status" />
                  </t-form-item>
                </t-col>
              </t-row>
            </t-space>
          </t-form>
        </div>
      </div>
    </t-drawer>
  </div>
</template>

<script setup lang="ts">
import { isJSON, isURL } from 'validator';
import { computed, ref, toRefs, watch } from 'vue';

import SteveAceEditor from '@/components/steveAceEditor/index.vue';
import SteveTextarea from '@/components/steveTextarea/index.vue';
import {
  compressJSON,
  convertStringToRegex,
  formatJSON,
  getArrayFieldToArray,
  getObjectPaths,
  getValueByPath,
  htmlToRules,
  isObjectEmpty,
  setValueByPath,
  showMessage,
  steveDeepCopy,
  urlToPath,
} from '@/utils/common';
import { deepCopy } from '@intlify/shared';
import { sourceFinderRule } from '@/pages/source/edit/sourceRule';

const props = defineProps({
  // 是否可见
  visible: {
    type: Boolean,
    default: false,
  },
  value: Object,
});

const { visible, value } = toRefs(props);

// 事件
const emit = defineEmits(['update:visible', 'confirm']);
const visibleTools = ref(false);
watch(visible, (v) => {
  visibleTools.value = v;
});

// 通知 visible
watch(visibleTools, (v) => {
  emit('update:visible', v);
});

// formData
const formData = ref({});
deepCopy(steveDeepCopy(sourceFinderRule), formData.value);

// json路径数组
const valueIsJsonPaths = getObjectPaths({
  header: {},
  params: {},
  list: [],
});
const jsonPath = getObjectPaths(formData.value);

watch(value, (v: any) => {
  if (!isObjectEmpty(v)) {
    jsonToFormData(v);
    groupTabsData.value = v.list;
  } else {
    formData.value.uuid = '';
    formData.value.name = '';
    formData.value.structure = '';
    formData.value.list = [];
    groupTabsData.value = [];
  }
});

const jsonToFormData = (json: any) => {
  for (const path of jsonPath) {
    let value = getValueByPath(json, path.value);
    if (getArrayFieldToArray(valueIsJsonPaths, 'value').includes(path.value)) {
      value = Object.keys(value).length > 0 ? JSON.stringify(value) : '';
    }
    setValueByPath(formData.value, path.value, value);
  }
};

const structureParams = ref([]);
watch(
  formData,
  (v) => {
    const { structure } = v;
    if (structure) {
      structureParams.value = [];
      const regex = /@{_(.*?)}/g;
      for (const match of structure.matchAll(regex)) {
        const [, type] = match; // 使用解构赋值获取匹配到的类型
        if (type && !structureParams.value.includes(type)) {
          structureParams.value.push(type);
        }
      }

      const list = [];
      for (const type of structureParams.value) {
        const group = getGroupItemByType(type);

        if (group) {
          list.push(group);
        } else {
          list.push({
            name: type,
            type,
            list: '',
          });
        }
      }
      groupTabsData.value = list;
    }
  },
  { deep: true },
);

// 构造类型
const structureType = ref(1);
watch(structureType, () => {
  onStructureSelectCancel();
});

// 选中的数据
const structureSelectText = ref('');
const structureSelectStart = ref(0);
const structureSelectEnd = ref(0);

// 判断是否已经选中
const isStructureSelect = computed(() => {
  return structureSelectEnd.value > 0 && structureSelectStart.value !== structureSelectEnd.value;
});

// 分组 Tabs
const groupTabsValue = ref(0);
const groupTabsData = ref([]);

// 转换
const onConversion = () => {
  const group = groupTabsData.value[groupTabsValue.value];
  if (group) {
    const rules = htmlToRules(group.list);
    if (rules && rules.length > 0) {
      for (const rule of rules) {
        let structureValue = formData.value.structure;
        // 如果转换的path不为url，构造体是url，那么需要删除构造体的host
        if (!isURL(rule.path) && isURL(structureValue)) {
          structureValue = urlToPath(structureValue);
        }

        // 如果转换的path为url，但构造体不是url，则需要删除path的host
        if (isURL(rule.path) && !isURL(structureValue)) {
          rule.path = urlToPath(rule.path);
        }

        // 处理value
        const regex = convertStringToRegex(structureValue);
        console.log(regex);
        const match = regex.exec(rule.path);
        rule.value = match ? match[groupTabsValue.value + 1] : '';
        delete rule.path;
      }
      groupTabsData.value[groupTabsValue.value].list = formatJSON(JSON.stringify(rules));
    } else {
      showMessage('请输入有效的HTML内容！', 'warning');
    }
  }
};

// 构造体选取
const onSelectStructure = (v: any) => {
  const { selectedText, selectionStart, selectionEnd } = getSelectedText(v.target);
  structureSelectText.value = selectedText;
  structureSelectStart.value = selectionStart;
  structureSelectEnd.value = selectionEnd;
};

// 设置构造体参数
const onStructureParamConfirm = () => {
  if (structureSelectText.value) {
    formData.value.structure = `${formData.value.structure.slice(0, structureSelectStart.value)}@{_${structureSelectText.value}}${formData.value.structure.slice(structureSelectEnd.value)}`;
    showMessage(`构造${structureSelectText.value}成功！`);
    onStructureSelectCancel();
  }
};

// 快捷输入
const onStructureParamShortcut = (value: any) => {
  formData.value.structure = `${formData.value.structure.slice(0, structureSelectStart.value)}@{${value}}${formData.value.structure.slice(structureSelectEnd.value)}`;
  onStructureSelectCancel();
};

// 取消构造体选中
const onStructureSelectCancel = () => {
  structureSelectText.value = '';
  structureSelectStart.value = 0;
  structureSelectEnd.value = 0;
};

// 确认
const onConfirm = () => {
  const data = formData.value;
  if (!data.name) {
    showMessage('请输入榜单名称', 'warning');
    return;
  }
  if (!data.structure) {
    showMessage('请输入构造地址', 'warning');
    return;
  }

  // 唯一识别码
  if (!data.uuid) {
    data.uuid = `${new Date().getTime()}`;
  }

  // 获取分组信息
  const groups = steveDeepCopy(groupTabsData.value);
  if (groups && groups.length > 0) {
    for (const group of groups) {
      if (group && isJSON(group.list)) {
        group.list = compressJSON(group.list);
      }
    }
    data.list = groups;
  }
  emit('confirm', steveDeepCopy(data));
};

// 根据类型获取对应的group项目
function getGroupItemByType(type: string) {
  let res;
  for (const item of groupTabsData.value) {
    if (item.type === type) {
      res = item;
    }
  }
  return res;
}

/**
 * 获取input中选中的数据
 * @param input
 */
function getSelectedText(input: HTMLInputElement) {
  let selectedText = '';
  const { selectionStart, selectionEnd } = input;
  if (selectionStart !== selectionEnd) {
    selectedText = input.value.substring(selectionStart, selectionEnd);
  } else {
    selectedText = '';
  }
  return { selectedText, selectionStart, selectionEnd };
}
</script>

<style lang="less" scoped>
:deep(.t-drawer__body) {
  padding: 0;

  .t-tabs__nav--card.t-tabs__nav-item:not(:first-of-type) {
    border-left: 0;
  }

  .t-tabs__nav--card.t-tabs__nav-item:last-of-type {
    border-right: 0;
  }
}

:deep(.t-space) {
  display: flex;
}

.steve-category-tools {
  .structure {
    &-body {
      padding: var(--td-comp-paddingLR-l);

      :deep(.t-tabs) {
        border: 1px solid var(--td-border-level-1-color);
      }

      .group-body {
        padding: var(--td-comp-paddingTB-l) var(--td-comp-paddingLR-l);
      }

      &__url {
        position: relative;

        &__type {
          position: absolute;
          z-index: 1;
          left: 0;
          top: -29px;
        }
      }
    }
  }
}
</style>
